package com.demo.view;

import android.content.Context;
import android.content.res.Configuration;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.text.TextPaint;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewConfiguration;
import android.widget.Scroller;

import androidx.annotation.IntRange;
import androidx.annotation.Nullable;

import com.module.commonui.R;
import com.tange.base.toolkit.DateUtil;
import com.tg.appcommon.android.TGLog;
import java.util.List;

/**
 * TimeRuleView
 * <p>
 * 时间尺控件
 * （仿“萤石云视频”里的时间选择控件）
 * <p>
 * 功能：
 * - 可选择一天（00:00 ~ 24:00）内的任一时刻，精确到秒级
 * - 可显示多个时间块
 * - 支持滑动及惯性滑动
 * - 支持缩放时间间隔
 * - 支持滑动与缩放的连续切换
 * <p>
 * 思路：
 * - 时间绘制思路参考
 * - 时间缩放，采用缩放手势检测器 ScaleGestureDetector
 * - 缩放的等级估算方式：进入默认比例为1，根据每隔所占的秒数与宽度，可估算出每个等级的宽度范围，再与默认等级对应的宽度相除，即可算出缩放比例
 * - 惯性滑动，使用速度追踪器 VelocityTracker
 * - 缩放与滑动之间的连续操作，ScaleGestureDetector 开始与结束的条件是第二个手指按下与松开，
 * 所以onTouchEvent()中应该使用 getActionMasked()来监听第二个手指的 DOWN(ACTION_POINTER_DOWN) 与 UP(ACTION_POINTER_UP) 事件，
 * MOVE 都是一样的
 * - 时间块，由起始时间与终止时间组成，采用一个有序的集合来装入即可
 * <p>
 * Author: Ralap
 * Description:
 * Date 2018/8/11
 */


public class TimeRuleView extends View {
    private static final String TAG = "TimeRuleView";
    public static final String TIME_SET_FROM_AUTO = "time_set_from_auto";
    public static final String TIME_SET_FROM_MANUL = "time_set_from_manual";
    public static final int MAX_TIME_VALUE = 24 * 3600;

    private int bgColor;
    /**
     * 刻度颜色
     */
    private int gradationColor;
    private int gradationColorImpl;
    private int landscapeGradationColor;
    /**
     * 时间块的高度
     */
    private float partHeight;
    private float partLeft;
    /**
     * 时间块的颜色
     */
    private int partColor;
    private int partColorImpl;
    private int landscapePartColor;

    /**
     * 刻度宽度
     */
    private float gradationWidth;
    /**
     * 秒、分、时刻度的长度
     */
    private float secondLen;
    private float minuteLen;
    private float hourLen;
    /**
     * 刻度数值颜色、大小、与时刻度的距离
     */
    private int gradationTextColor;
    private int landscapeGradationTextColor;
    private int gradationTextColorImpl;
    private float gradationTextSize;


    private int fixedTime = 0;

    /**
     * 当前时间，单位：s
     */
    private volatile @IntRange(from = 0, to = MAX_TIME_VALUE)
    int currentTime;


    private boolean mIsFlinging = false; //当前是否在惯性滑动

    public boolean isFromAuto() {
        return TIME_SET_FROM_AUTO.equals(mCurTimeFrom);
    }

    public void onConfigurationChanged(int orientation) {
        if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
            gradationColorImpl = landscapeGradationColor;
            partColorImpl = landscapePartColor;
            indicatorColorImpl = landscapeIndicatorColor;
            gradationTextColorImpl = landscapeGradationTextColor;
        } else {
            indicatorColorImpl = indicatorColor;
            gradationColorImpl = gradationColor;
            partColorImpl = partColor;
            gradationTextColorImpl = gradationTextColor;
        }
        mPaint.setColor(gradationColorImpl);
        mBlackPaint.setColor(gradationColorImpl);
        mPaint.setColor(partColorImpl);
    }

    public void setCurTimeFrom(String from) {
        this.mCurTimeFrom = from;
    }

    private volatile String mCurTimeFrom = TIME_SET_FROM_AUTO;
    /**
     * 指针颜色
     */
    private int indicatorColor;
    private int indicatorColorImpl;
    private int landscapeIndicatorColor;
    private boolean canComputeTime = false;
    /**
     * 最小单位对应的单位秒数值，一共四级: 10s、1min、5min、15min
     * 与 {@link #mPerTextCounts} 和 {@link #mPerCountScaleThresholds} 对应的索引值
     * <p>
     * 可以组合优化成数组
     */
    private static int[] mUnitSeconds = {
            10, 10, 10, 10,
            60, 60,
            5 * 60, 5 * 60,
            15 * 60, 15 * 60, 15 * 60, 15 * 60, 15 * 60, 15 * 60
    };

    /**
     * 数值显示间隔。一共13级，第一级最大值，不包括
     */
    @SuppressWarnings("all")
    private static int[] mPerTextCounts = {
            60, 60, 2 * 60, 4 * 60, // 10s/unit: 最大值, 1min, 2min, 4min
            5 * 60, 10 * 60, // 1min/unit: 5min, 10min
            20 * 60, 30 * 60, // 5min/unit: 20min, 30min
            3600, 2 * 3600, 3 * 3600, 4 * 3600, 5 * 3600, 6 * 3600 // 15min/unit
    };

    /**
     * 与 {@link #mPerTextCounts} 对应的阈值，在此阈值与前一个阈值之间，则使用此阈值对应的间隔数值
     * 如：1.5f 代表 4*60 对应的阈值，如果 mScale >= 1.5f && mScale < 1.8f，则使用 4*60
     * <p>
     * 这些数值，都是估算出来的
     */
    @SuppressWarnings("all")
    private float[] mPerCountScaleThresholds = {
            6f, 3.6f, 1.8f, 1.5f, // 10s/unit: 最大值, 1min, 2min, 4min
            0.8f, 0.4f,   // 1min/unit: 5min, 10min
            0.25f, 0.125f, // 5min/unit: 20min, 30min
            0.07f, 0.04f, 0.03f, 0.025f, 0.02f, 0.015f // 15min/unit: 1h, 2h, 3h, 4h, 5h, 6h
    };
    /**
     * 默认mScale为1
     */
    private float mScale = 1;
    /**
     * 1s对应的间隔，比较好估算
     */
    private final float mOneSecondGap = dp2px(12) / 60f;
    /**
     * 当前最小单位秒数值对应的间隔
     */
    private float mUnitGap = mOneSecondGap * 60;
    /**
     * 默认索引值
     */
    private int mPerTextCountIndex = 5;
    /**
     * 一格代表的秒数。默认1min
     */
    private int mUnitSecond = mUnitSeconds[mPerTextCountIndex];

    /**
     * 数值文字宽度的一半：时间格式为“00:00”，所以长度固定
     */
    private final float mTextHalfWidth;
    private final float mTextHalfHeight;

    /**
     * 数值文字宽度的一半：时间格式为“00:00:00”，所以长度固定
     */
    private final int MIN_VELOCITY;
    private final int SCROLL_SLOP;
    private final int MAX_VELOCITY;

    /**
     * 当前时间与 00:00 的距离值
     */
    private float mCurrentDistance;

    private Paint mPaint;
    private TextPaint mTextPaint;
    private TextPaint mTimePaint;
    private Paint mBlackPaint;
    private Scroller mScroller;
    private VelocityTracker mVelocityTracker;

    /**
     * 缩放手势检测器
     */
    private ScaleGestureDetector mScaleGestureDetector;

    private int mWidth, mHeight;
    private int mHalfWidth;

    private int mInitialY;
    private int mLastY;
    private boolean isMoving;
    private boolean isScaling;

    private Context mContext;
    private List<TimePart> mTimePartList;
    private OnTimeChangedListener mListener;

    public interface OnTimeChangedListener {
        void onScrolled(int newTimeValue);


        void onTimeChanged(int newTimeValue);

        boolean canScrolled();
    }

    /**
     * 时间片段
     */
    public static class TimePart {
        /**
         * 起始时间，单位：s，取值范围∈[0, 86399]
         * 0       —— 00:00:00
         * 86399   —— 23:59:59
         */
        public int startTime;

        /**
         * 结束时间，必须大于{@link #startTime}
         */
        public int endTime;

        /**
         * 时间片段颜色显示，根据时间类型
         * motion  移动监测
         * sound    声音
         * body     人形
         */
        public String eventType;

        /**
         * 云视频OssId
         */
        public String ossId;

        @Override
        public boolean equals(Object obj) {
            TimePart t = (TimePart) obj;
            return t != null && this.startTime == t.startTime && this.endTime == t.endTime;
        }
    }

    public TimeRuleView(Context context) {
        this(context, null);
    }

    public TimeRuleView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public TimeRuleView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initAttrs(context, attrs);

        init(context);
        initScaleGestureDetector(context);

        mTextHalfWidth = mTextPaint.measureText("00:00") * .5f;
        mTextHalfHeight = (-mTextPaint.ascent() + mTextPaint.descent()) / 2;
        ViewConfiguration viewConfiguration = ViewConfiguration.get(context);
        SCROLL_SLOP = viewConfiguration.getScaledTouchSlop();
        MIN_VELOCITY = viewConfiguration.getScaledMinimumFlingVelocity();
        MAX_VELOCITY = viewConfiguration.getScaledMaximumFlingVelocity();

        calculateValues();
    }

    private void initAttrs(Context context, AttributeSet attrs) {
        TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.TimeRuleView);
        bgColor = ta.getColor(R.styleable.TimeRuleView_bgColor, Color.parseColor("#EEEEEE"));

        gradationColor = ta.getColor(R.styleable.TimeRuleView_gradationColor, Color.parseColor("#BAD3EC"));
        gradationColorImpl = gradationColor;
        landscapeGradationColor = ta.getColor(R.styleable.TimeRuleView_landscapeGradationColor, Color.parseColor("#0D0E10"));

        partHeight = ta.getDimension(R.styleable.TimeRuleView_trv_partHeight, dp2px(20));
        partLeft = ta.getDimension(R.styleable.TimeRuleView_trv_partLeft, dp2px(50));
        partColor = ta.getColor(R.styleable.TimeRuleView_trv_partColor, Color.parseColor("#5C6268"));
        partColorImpl = partColor;
        landscapePartColor = ta.getColor(R.styleable.TimeRuleView_trv_landscapePartColor, Color.parseColor("#0D2F4C"));
        gradationWidth = ta.getDimension(R.styleable.TimeRuleView_trv_gradationWidth, 2);
        secondLen = ta.getDimension(R.styleable.TimeRuleView_trv_secondLen, dp2px(3));
        minuteLen = ta.getDimension(R.styleable.TimeRuleView_trv_minuteLen, dp2px(5));
        hourLen = ta.getDimension(R.styleable.TimeRuleView_trv_hourLen, dp2px(10));
        gradationTextColor = ta.getColor(R.styleable.TimeRuleView_trv_gradationTextColor, Color.GRAY);
        landscapeGradationTextColor = ta.getColor(R.styleable.TimeRuleView_trv_landscapeGradationTextColor, Color.GRAY);
        gradationTextColorImpl = gradationTextColor;
        gradationTextSize = ta.getDimension(R.styleable.TimeRuleView_trv_gradationTextSize, sp2px(12));
        currentTime = ta.getInt(R.styleable.TimeRuleView_trv_currentTime, 0);
        indicatorColor = ta.getColor(R.styleable.TimeRuleView_indicatorLineColor, Color.parseColor("#FE753E"));
        indicatorColorImpl = indicatorColor;
        landscapeIndicatorColor = ta.getColor(R.styleable.TimeRuleView_landscapeIndicatorLineColor, Color.parseColor("#2D9CFC"));
        ta.recycle();
    }

    private void calculateValues() {
        mCurrentDistance = currentTime / mUnitSecond * mUnitGap;
    }

    private void init(Context context) {
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mBlackPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mBlackPaint.setStrokeWidth(partHeight);
        mBlackPaint.setColor(gradationColorImpl);
        mContext = context;
        mTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
        mTextPaint.setTextSize(gradationTextSize);
        mTextPaint.setColor(gradationTextColorImpl);
        mTimePaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
        mTimePaint.setTextSize(sp2px(14));
        mTimePaint.setTextAlign(Paint.Align.CENTER);
        mTimePaint.setColor(Color.WHITE);
        mScroller = new Scroller(context);
        mHalfWidth = context.getResources().getDimensionPixelOffset(R.dimen.time_rule_margin_top);
    }

    private void initScaleGestureDetector(Context context) {
        mScaleGestureDetector = new ScaleGestureDetector(context, new ScaleGestureDetector.OnScaleGestureListener() {

            /**
             * 缩放被触发(会调用0次或者多次)，
             * 如果返回 true 则表示当前缩放事件已经被处理，检测器会重新积累缩放因子
             * 返回 false 则会继续积累缩放因子。
             */
            @Override
            public boolean onScale(ScaleGestureDetector detector) {
                final float scaleFactor = detector.getScaleFactor();
                final float maxScale = mPerCountScaleThresholds[0];
                final float minScale = mPerCountScaleThresholds[mPerCountScaleThresholds.length - 1];
                TGLog.d("onScale:mScale" + minScale + ", maxScale = " + maxScale+", scaleFactor= " + scaleFactor);
                if (scaleFactor > 1 && mScale >= maxScale) {
                    // 已经放大到最大值
                    return true;
                } else if (scaleFactor < 1 && mScale <= minScale) {
                    // 已经缩小到最小值
                    return true;
                }


                mScale *= scaleFactor;
                mScale = Math.max(minScale, Math.min(maxScale, mScale));
                mPerTextCountIndex = findScaleIndex(mScale);

                mUnitSecond = mUnitSeconds[mPerTextCountIndex];
                mUnitGap = mScale * mOneSecondGap * mUnitSecond;
                mCurrentDistance = (float) currentTime / mUnitSecond * mUnitGap;
                float maxDistance = MAX_TIME_VALUE / mUnitSecond * mUnitGap;
                TGLog.d(TAG,"onScale:mCurrentDistance" + mCurrentDistance);
                mCurrentDistance = Math.min(maxDistance, Math.max(0, mCurrentDistance));
                TGLog.d(TAG,"onScale:mScale" + mScale + ", mCurrentDistance = " + mCurrentDistance + ", maxDistance = " + maxDistance);
                invalidate();
                return true;
            }

            @Override
            public boolean onScaleBegin(ScaleGestureDetector detector) {
                isScaling = true;
                return true;
            }

            @Override
            public void onScaleEnd(ScaleGestureDetector detector) {
                isScaling = false;
            }
        });

    }

    /**
     * 二分法查找缩放值对应的索引值
     */
    private int findScaleIndex(float scale) {
        final int size = mPerCountScaleThresholds.length;
        int min = 0;
        int max = size - 1;
        int mid = (min + max) >> 1;
        while (!(scale >= mPerCountScaleThresholds[mid] && scale < mPerCountScaleThresholds[mid - 1])) {
            if (scale >= mPerCountScaleThresholds[mid - 1]) {
                // 因为值往小区，index往大取，所以不能为mid -1
                max = mid;
            } else {
                min = mid + 1;
            }
            mid = (min + max) >> 1;
            if (min >= max) {
                break;
            }
            if (mid == 0) {
                break;
            }
        }
        return mid;
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        mWidth = MeasureSpec.getSize(widthMeasureSpec);
        mHeight = MeasureSpec.getSize(heightMeasureSpec);

        // 只处理wrap_content的高度，设置为80dp
        if (MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.AT_MOST) {
            mWidth = dp2px(60);
        }
        mHalfWidth = mContext.getResources().getDimensionPixelOffset(R.dimen.time_rule_margin_top);
        setMeasuredDimension(mWidth, mHeight);
    }


    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (mListener != null && !mListener.canScrolled()) {
            return true;
        }
        final int actionIndex = event.getActionIndex();
        final int actionMasked = event.getActionMasked();
        final int y = (int) event.getY();
        if (event.getPointerCount() > 1) {
            mScaleGestureDetector.onTouchEvent(event);
        }

        buildVelocityTracker();
        mVelocityTracker.addMovement(event);

        switch (actionMasked) {
            case MotionEvent.ACTION_DOWN:
                TGLog.d(TAG,"ACTION_DOWN:" + mScroller.isFinished() + ", mIsFlinging:" + mIsFlinging);
                isMoving = false;
                mInitialY = y;
                forceFinished();
                break;
            case MotionEvent.ACTION_POINTER_DOWN:
                TGLog.d(TAG,"ACTION_POINTER_DOWN:" + mScroller.isFinished() + ", mIsFlinging:" + mIsFlinging);
                // 只要第二手指按下，就禁止滑动
                isScaling = true;
                isMoving = false;
                mIsFlinging = false;
                break;
            case MotionEvent.ACTION_MOVE:
                TGLog.d(TAG,"ACTION_MOVE isScaling" + isScaling);
                if (isScaling) {
                    break;
                }
                int dy = y - mLastY;
                if (!isMoving) {
                    if (Math.abs(y - mInitialY) <= SCROLL_SLOP) {
                        break;
                    }
                    isMoving = true;
                }
                mCurrentDistance -= dy;
                TGLog.d(TAG,"ACTION_UP AmInitialY - y" + (mInitialY - y) + ", dy = " +dy);
                if (mInitialY - y != 0) {
                    computeTime(false);
                }

                break;
            case MotionEvent.ACTION_UP:
                TGLog.d("ACTION_UP ACTION_UP isScaling" + isScaling);
                if (isScaling || !isMoving || mInitialY - y == 0) {
                    break;
                }
                mVelocityTracker.computeCurrentVelocity(1000, MAX_VELOCITY);
                final int yVelocity = (int) mVelocityTracker.getYVelocity();
                final int maxDistance = (int) (MAX_TIME_VALUE / mUnitSecond * mUnitGap);
                // 限定范围
                float modifyDistance = Math.min(maxDistance, Math.max(0, mCurrentDistance));
                TGLog.d(TAG,"MIN_VELOCITY" + MIN_VELOCITY + ", MAX_VELOCITY = " + MAX_VELOCITY + ", distance = " + Math.abs(maxDistance-mCurrentDistance) + ", modifyDistance =" + modifyDistance);
                if (Math.abs(yVelocity) >= MIN_VELOCITY && Math.abs(maxDistance-modifyDistance) >= MIN_VELOCITY) {
                    // 惯性滑动
                    mIsFlinging = true;
                    TGLog.d(TAG,"maxDistance：" + maxDistance + ", yVelocity = " + yVelocity + ", mCurrentDistance = " + mCurrentDistance);
                    mScroller.fling(0, (int) mCurrentDistance, 0, -yVelocity, 0, 0, 0, maxDistance);
                    invalidate();
                } else {
                    mIsFlinging = false;
                    setCurTimeFrom(TIME_SET_FROM_MANUL);
                    computeTime(true);
                }
                break;
            case MotionEvent.ACTION_POINTER_UP:
                // 两个中的有一个手指被抬起，允许滑动。同时把未抬起的手机当前位置赋给初始X
                isScaling = false;
                int restIndex = actionIndex == 0 ? 1 : 0;
                mInitialY = (int) event.getY(restIndex);
                break;
            default:
                break;
        }
        mLastY = y;
        return true;
    }

    private void forceFinished() {
        if (!mScroller.isFinished()) {
            mScroller.forceFinished(true);
            if (mIsFlinging) {
                mIsFlinging = false;
                mCurrentDistance = mScroller.getCurrY();
                computeTime(true);
            }
        }
    }

    private void buildVelocityTracker() {
        if (mVelocityTracker == null) {
            mVelocityTracker = VelocityTracker.obtain();
        }
    }


    @Override
    public void computeScroll() {
        TGLog.d("computeScroll : ");
        if (mIsFlinging) {
            if (mScroller.computeScrollOffset()) {
                TGLog.d(TAG,"computeScroll : " + ", mScroller.isFinished() = " + mScroller.isFinished());
                mCurrentDistance = mScroller.getCurrY();
                boolean finish = mScroller.isFinished();
                mIsFlinging = !finish;
                computeTime(finish);
            }
        }
    }


    private void computeTime(boolean isChanged) {
        TGLog.d(TAG,"isChanged isChanged " + isChanged);
        if (mListener == null || !mListener.canScrolled()) {
            return;
        }
        // 不用转float，肯定能整除
        float maxDistance = MAX_TIME_VALUE / mUnitSecond * mUnitGap;
        // 限定范围
        mCurrentDistance = Math.min(maxDistance, Math.max(0, mCurrentDistance));
        currentTime = (int) (mCurrentDistance / mUnitGap * mUnitSecond) + fixedTime;
        int curTime = MAX_TIME_VALUE - currentTime;
        TGLog.d(TAG,"PlayBackFragment computeTime " + curTime + " " + (isChanged ? "isChanged" : ""));
        if (mListener != null) {
            if (isChanged) {
                mListener.onTimeChanged(curTime);
            } else {
                mListener.onScrolled(curTime);
            }
        }
        invalidate();
    }


    @Override
    protected void onDraw(Canvas canvas) {

        try {
            // 背景
            canvas.drawColor(bgColor);

            // 刻度
            drawRule(canvas);

            // 时间段
            drawTimeParts(canvas);
        } catch (Throwable ex) {
            // ignore
        }

    }

    /**
     * 绘制刻度
     */
    private void drawRule(Canvas canvas) {
        // 移动画布坐标系
        canvas.save();
        canvas.translate(0, partHeight);
        mPaint.setColor(gradationColorImpl);
        mTextPaint.setColor(gradationTextColorImpl);
        mPaint.setStrokeWidth(gradationWidth);
        // 刻度
        int start = MAX_TIME_VALUE;
        //TODO
        float offset = mHalfWidth - mCurrentDistance - partHeight;
        final int perTextCount = mPerTextCounts[mPerTextCountIndex];
        float horizionX = partLeft - 10;
        while (start >= 0) {
            // 刻度
            if (start % 3600 == 0) {
                // 时刻度
                canvas.drawLine(horizionX - hourLen, offset, horizionX, offset, mPaint);
            } else if (start % 60 == 0) {
                // 分刻度
                canvas.drawLine(horizionX - minuteLen, offset, horizionX, offset, mPaint);
            } else {
                // 秒刻度
                canvas.drawLine(horizionX - secondLen, offset, horizionX, offset, mPaint);
            }
            // 时间数值
            if (start % perTextCount == 0) {
                String text = DateUtil.formatTimeHHmm(start);
                canvas.drawText(text, (partLeft - hourLen) / 2 - mTextHalfWidth, offset + mTextHalfHeight / 2, mTextPaint);
            }
            start -= mUnitSecond;
            offset += mUnitGap;
        }
        canvas.restore();
    }

    /**
     * 绘制时间段
     */
    private void drawTimeParts(Canvas canvas) {
        mPaint.setColor(partColorImpl);
        mPaint.setStrokeWidth(partHeight);
        float start, end;
        final float secondGap = mUnitGap / mUnitSecond;
        float horizonX = partLeft;
        canvas.drawLine(horizonX, 0, horizonX, mHeight, mBlackPaint);
        if (mTimePartList != null && mTimePartList.size() > 0) {
            for (int i = mTimePartList.size() - 1; i >= 0; i--) {
                TimePart part = null;

                if (i >= 0 && i < mTimePartList.size()) {
                    try {
                        part = mTimePartList.get(i);
                    } catch (IndexOutOfBoundsException indexOutOfBoundsException) {
                        part = null;
                    }
                }

                if (part==null) continue;
                if (!TextUtils.isEmpty(part.eventType)) {
                    mPaint.setColor(indicatorColorImpl);
                } else {
                    mPaint.setColor(partColorImpl);
                }
                if (mTimePartList.get(i) == null) continue;
                start = mHalfWidth - mCurrentDistance + (MAX_TIME_VALUE - mTimePartList.get(i).endTime) * secondGap;
                end = mHalfWidth - mCurrentDistance + (MAX_TIME_VALUE - mTimePartList.get(i).startTime) * secondGap;
                canvas.drawLine(horizonX, start, horizonX, end, mPaint);
            }
        }
    }


    private int dp2px(float dp) {
        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, getResources().getDisplayMetrics());
    }

    private int sp2px(float sp) {
        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, sp, getResources().getDisplayMetrics());
    }

    /**
     * 设置时间变化监听事件
     *
     * @param listener 监听回调
     */
    public void setOnTimeChangedListener(OnTimeChangedListener listener) {
        this.mListener = listener;
    }

    /**
     * 设置时间块（段）集合
     *
     * @param timePartList 时间块集合
     */
    public void setTimePartList(List<TimePart> timePartList) {
        this.mTimePartList = timePartList;
        postInvalidate();
    }


    public void scrolltoTime(@IntRange(from = 0, to = MAX_TIME_VALUE) int time) {
        this.currentTime = MAX_TIME_VALUE - time;
        float secondGap = mUnitGap / mUnitSecond;
        mCurrentDistance = secondGap * this.currentTime;
        postInvalidate();
        if (mListener != null && mListener.canScrolled()) {
            TGLog.d(TAG,"scrolltoTime = " + time);
            mListener.onTimeChanged(time);
        }
    }

    /**
     * 设置当前时间
     *
     * @param currentTime 当前时间
     * @param updateTime  是否需要更新时间，会重新取数据
     */
    public void setCurrentTime(@IntRange(from = 0, to = MAX_TIME_VALUE) int currentTime, boolean updateTime) {
        this.currentTime = MAX_TIME_VALUE - currentTime;
        float secondGap = mUnitGap / mUnitSecond;
        float unitSize = secondGap * this.currentTime;
        int dxy = (int) (unitSize - mCurrentDistance);
        if (mScroller.isFinished()) {
            mScroller.startScroll(mScroller.getCurrX(), (int) mCurrentDistance, 0, dxy);
        }

        mCurrentDistance = unitSize;
        canComputeTime = updateTime;
        postInvalidate();
        if (canComputeTime) {
            canComputeTime = false;
            computeTime(true);
        }
    }

    public int getCurrentTime() {
        return MAX_TIME_VALUE - currentTime;
    }
}